package com.sprite.framework.entity.model;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.sprite.utils.UtilCollection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.sprite.framework.entity.EntityException;
import com.sprite.utils.UtilString;
import com.sprite.utils.UtilXml;

/**
 * 实体模型构建类
 * @author Jackl
 */
public class EntityModelReader {

	// key is entityName
	private Map<String, ModelEntity> modelEntities = new HashMap<>();

	private List<ModelEntity> modelExtends = new LinkedList<>();

	private ModelEntity baseEntity = new ModelEntity();
	
	/**
	 * 自增序列实体类
	 */
	private  ModelEntity sequenceEntity = new ModelEntity();
	
	public EntityModelReader() {
		sequenceEntity.setEntityName("SequenceItem");
		sequenceEntity.setTableName(addUnderscores("SequenceItem", null));
		sequenceEntity.addModelField(new ModelField("sequenceId", "sequence_id", "str-short", true));
		sequenceEntity.addModelField(new ModelField("sequenceValue", "sequence_value", "int-long"));
	}

	/**
	 * 解析Document 构建ModelEntity
	 * @param document doc
	 */
	public void buildModel(Document document) {
		Element docElement = document.getDocumentElement();
		if(!"entity-model".equals(docElement.getTagName())){
			throw new IllegalArgumentException("entity model error");
		}

		docElement.normalize();
		String defaultPackage = docElement.getAttribute("package");
		
		List<Element> entityList = UtilXml.childElementList(docElement, "entity");
		
		List<Element> baseEntityList = UtilXml.childElementList(docElement, "baseEntity");
		for(Element element :baseEntityList) {
			if(baseEntity == null) {
				baseEntity = buildModelEntity(element, defaultPackage);
			}else {
				baseEntity.extend(buildModelEntity(element, defaultPackage));
			}
		}

		ModelEntity entity = null;
		for(Element element : entityList) {
			entity = buildModelEntity(element, defaultPackage);
			modelEntities.put(entity.getEntityName(), entity);
		}
		
		entityList = UtilXml.childElementList(docElement, "entityExtend");
		
		for(Element element : entityList) {
			entity = buildModelEntity(element, defaultPackage);
			modelExtends.add(entity);
		}
	}

	/**
	 * 构建ModelField配置
	 * @param document doc
	 * @param databaseType 数据库类型
	 */
	public void buildModelFieldType(Document document, String databaseType) {
		Element docElement = document.getDocumentElement();
		if(!"fieldtype-def".equals(docElement.getTagName())){
			throw new IllegalArgumentException("entity model field type error");
		}

		List<Element> typeList = UtilXml.childElementList(docElement, "type");
		
		for(Element type : typeList) {
			ModelFieldType fieldType = new ModelFieldType();
			fieldType.setSqlType(type.getAttribute("sqlType"));
			fieldType.setType(type.getAttribute("type"));
			ModelEntityUtil.addModelFieldType(fieldType);
		}

		ModelEntityUtil.setDatabaseType(databaseType);
	}

	/**
	 * 构建ModelEntity
	 * @param entity
	 * @param defaultPackage 默认的包名
	 * @return
	 */
	private ModelEntity buildModelEntity(Element entity, String defaultPackage) {
		ModelEntity modelEntity =new ModelEntity();

		String packageName = defaultPackage;
		String entityName = entity.getAttribute("entityName");
		String tableName = entity.getAttribute("tableName");
		String singleName = entityName;

		if(entityName.indexOf('.') < 0) {
			entityName = defaultPackage+"."+entityName;
		}else {
			singleName = entityName.substring(entityName.indexOf('.')+1);
			packageName = entityName.substring(0, entityName.indexOf('.'));
		}

		tableName = addUnderscores(tableName, entityName);

		modelEntity.setPackageName(packageName);
		modelEntity.setEntityName(entityName);
		modelEntity.setEntitySingleName(singleName);
		modelEntity.setTableName(tableName);

		List<Element> fields = UtilXml.childElementList(entity);

		String filedName = null;
		String colName = null;
		for(Element field : fields) {
			filedName = field.getAttribute("name");
			colName = field.getAttribute("colName");

			colName = addUnderscores(colName, filedName);

			ModelField modelField = new ModelField(filedName, colName, field.getAttribute("type"));
			modelField.setKey("key".equals(field.getTagName()));
			modelEntity.addModelField(modelField);
		}

		return modelEntity;
	}


	/**
	 * <p>1、将实体的扩展配置合并到实体定义中，见标签 entityExtend</p>
	 * <p>2、将基础实体配置合并到实体定义中，见标签 baseEntity</p>
	 */
	public void merge() {
		for(ModelEntity extend: modelExtends) {
			ModelEntity modelEntity = modelEntities.get(extend.getEntityName());
			if(modelEntity == null) {
				throw new EntityException("not found modeEntity: "+ extend.getEntityName());
			}
			modelEntity.extend(extend);
		}
		
		for(ModelEntity modelEntity : modelEntities.values()) {
			modelEntity.extend(baseEntity);
		}
		
		// 是否存在自增序列
		boolean hasSequenceId = false;
		for(ModelEntity modelEntity : modelEntities.values()) {
			List<ModelField> keys = modelEntity.getKeys();
			if(UtilCollection.isEmpty(keys)) {
				continue;
			}
			for(ModelField keyField : keys){
				if("sequence".equals(keyField.getType())) {
					hasSequenceId = true;
					break;
				}
			}
			if(hasSequenceId){
				break;
			}
		}
		
		ModelEntityUtil.addModelEntities(modelEntities.values());

		if(hasSequenceId) {
			ModelEntityUtil.addModelEntity(sequenceEntity);
		}
	}


	/**
	 * <p>1、如果name 是空，使用默认值</p>
	 * <p>2、将英文句号替换为下滑线</p>
	 * <p>3、驼峰命名方式用下滑下分割，例：</p>
	 * <p>"stuName" : "stu_name"</p>
	 * <p>"StuName" :  "stu_name"</p>
	 * <p>"SName" :  "s_name"</p>
	 * <p>"STName" :  "s_t_name"</p>
	 * @param name 实体全名，包含包名
	 * @param defaultValue 默认值
	 * @return 字符串
	 */
	protected static String addUnderscores(String name, String defaultValue) {
		if(UtilString.isEmpty(name)) {
			name = defaultValue;
		}

		StringBuilder buf = new StringBuilder();
		char[] chars = name.toCharArray();

		for(int i =0; i< chars.length; i++){
			if(chars[i] == '.'){
				if(i>0 && chars[i-1] != '.')
				buf.append("_");
				continue;
			}

			if(i>0 && Character.isUpperCase(chars[i]) && chars[i-1] != '.'){
				buf.append("_");
			}
			buf.append(chars[i]);
		}
		return buf.toString().toLowerCase();
	}

}
